/*-
 * BaseRepository.java
 *
 * Date: 2016年5月16日
 * Time: 上午11:47:35
 *
 * 版权所有©2012-2013 rengh
 */

package com.lmx.repoDomain.repository;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import com.lmx.common.constants.ICommonConstants;
import com.lmx.common.context.ActionContextHolder;
import com.lmx.common.util.CommonUtil;
import com.lmx.persistence.service.CommonService;
import com.lmx.persistence.service.GenericService;
import com.lmx.repoDomain.tmodel.BaseDataEntity;
import com.lmx.repoDomain.tmodel.PageInfo;
import com.lmx.repoDomain.tmodel.unpersis.ExportParam;

import io.katharsis.queryParams.QueryParams;
import io.katharsis.repository.MetaRepository;
import io.katharsis.repository.ResourceRepository;
import io.katharsis.repository.annotations.JsonApiDelete;
import io.katharsis.repository.annotations.JsonApiFindAll;
import io.katharsis.repository.annotations.JsonApiFindAllWithIds;
import io.katharsis.repository.annotations.JsonApiFindOne;
import io.katharsis.repository.annotations.JsonApiMeta;
import io.katharsis.repository.annotations.JsonApiSave;
import io.katharsis.response.MetaInformation;

/**
 * jsonapi repo基础类
 *
 * @author lmx
 * @version 1.00
 */
public abstract class BaseRepository<T> implements ResourceRepository<T, Long>, MetaRepository<T> {
	private static final AtomicLong ID_GENERATOR = new AtomicLong(124);
	private Log logger = LogFactory.getLog(this.getClass());

	private Class<T> type;
	@Autowired
	ApplicationContext applicationContext;
	@Autowired
	protected GenericService dslJpaService;

	@Autowired
	protected CommonService commonService;

	public BaseRepository() {
		// Type type = getClass().getGenericSuperclass();
		// while (!(type instanceof ParameterizedType)
		// || ((ParameterizedType) type).getRawType() != BaseRepository.class) {
		// if (type instanceof ParameterizedType) {
		// type = ((Class<?>) ((ParameterizedType)
		// type).getRawType()).getGenericSuperclass();
		// } else {
		// type = ((Class<?>) type).getGenericSuperclass();
		// }
		// }
		// this.type = (Class<T>) ((ParameterizedType)
		// type).getActualTypeArguments()[0];
	}

	public BaseRepository(final Class<T> type) {
		this.type = type;
	}

	protected Class<T> getEntityType() {
		return this.type;
	}

	@Override
	@JsonApiFindOne
	public T findOne(final Long id, final QueryParams requestParams) {
		final T t = (T) dslJpaService.findById(id);
		return t;
	}

	@Override
	@JsonApiFindAll
	public Iterable<T> findAll(final QueryParams requestParams) {
		Long tenantId = ActionContextHolder.getContext().getTenantId();
		ExportParam poiParam = ActionContextHolder.getContext().getExportParam();
		if (poiParam != null && StringUtils.isNotBlank(poiParam.getTitle())) {
			return this.dslJpaService.export(requestParams, tenantId, poiParam);
		}
		if (tenantId != null) {
			return dslJpaService.findAllBusi(requestParams, tenantId);
		} else {
			return dslJpaService.findAll(requestParams);
		}
	}

	@Override
	@JsonApiMeta
	public MetaInformation getMetaInformation(Iterable<T> resources, QueryParams params) {
		PageInfo info = PageInfo.getInstance();// 安全线程中获取分页信息
		if (info.getTotalCount() == null)
			info = null; // 无分页信息
		PageInfo.clear();// 清空安全线程
		logger.debug("pageInfo : " + info);
		return info;
	}

	public Iterable<T> findAll() {
		return dslJpaService.findAll();
	}

	@Override
	@JsonApiFindAllWithIds
	public Iterable<T> findAll(final Iterable<Long> ids, final QueryParams requestParams) {
		return null;
	}

	@Override
	@JsonApiDelete
	public void delete(final Long id) {
		dslJpaService.deleteById(id);
	}

	@Override
	@JsonApiSave
	public <S extends T> S save(final S entity) {
		String entityClassName = entity.getClass().getName();
		final BaseDataEntity bd = (BaseDataEntity) entity;
		// 此三个model专门用于存放payload数据，非entity不做save操作
		final Boolean notPayloadData = !"com.lmx.repoDomain.tmodel.StaffWorkTimeSetting".equals(entityClassName)
				&& !"com.lmx.repoDomain.tmodel.CustomerNursingPlan".equals(entityClassName)
				&& !"com.lmx.repoDomain.tmodel.CustomerNursingPlanModel".equals(entityClassName)
				&& !"com.lmx.repoDomain.tmodel.HealthInfoEntry".equals(entityClassName);
		if (notPayloadData) {
			if (bd.getId() == null) {
				dslJpaService.create(bd);
			} else {
				dslJpaService.update(bd);
			}
		}
		Map<String, List<Object>> map = ActionContextHolder.getContext().getPayloadDatas();
		if (map == null || map.size() < 1) {
			return (S) bd;
		}
		String pName = "";
		try {
			if (map.size() > 2) {
				pName = ((String) map.get("reverse").get(0)).split(",")[0];// 获取reverse类名
			} else {
				pName = (String) map.get("reverse").get(0);// 获取reverse类名
			}
			//payload为空 删除操作将相关中间表数据删除
			if (notPayloadData) {
				for(String key : map.keySet()){
					if("reverse".equals(key)){
						
					}else{
						Class<?> clsEntity = Class.forName(entityClassName);
						Field[] fields = clsEntity.getDeclaredFields();
						for (Field field : fields) {
							if (field.getName().equals(key)) {
								System.out.println(field.getGenericType());
								if(field.getGenericType().toString().contains("java.util.List")){
									String dataSimpleClassName = field.getGenericType().toString().replaceAll("java.util.List<", "").replace(">", "");
									//String dataClassName = dataSimpleClassName.split("\\.")[4];
									Class<?> clsData = Class.forName(dataSimpleClassName);
									if ((map.get(key) == null || map.get(key).size() == 0)
											&& this.checkFieldExit(clsData, pName)) {
										try {
											commonService.deleteEntity(dataSimpleClassName, pName, bd.getId(), null);
										} catch (Exception e) {
											logger.debug("base delete error1 " + dataSimpleClassName + " " + pName + " "
													+ bd.getId() + " " + " " + e);
										}
									}
								}
								if(field.getGenericType().toString().contains("java.util.Set")){
									String dataSimpleClassName = field.getGenericType().toString().replaceAll("java.util.Set<", "").replace(">", "");
									//String dataClassName = dataSimpleClassName.split("\\.")[4];
									Class<?> clsData = Class.forName(dataSimpleClassName);
									if ((map.get(key) == null || map.get(key).size() == 0)
											&& this.checkFieldExit(clsData, pName)) {
										try {
											commonService.deleteEntity(dataSimpleClassName, pName, bd.getId(), null);
										} catch (Exception e) {
											logger.debug("base delete error2 " + dataSimpleClassName + " " + pName + " "
													+ bd.getId() + " " + " " + e);
										}
									}
								}
							}
						}
					}
				}
			}
			//payload数据不为空，保存或修改中间表数据
			for (String key : map.keySet()) {
				List<Object> datas = new ArrayList<>();
				List<Object> datasTemp;
				if ("reverse".equals(key)) {
					logger.debug("reverse in");
				} else {
					datasTemp = map.get(key);
					int deleteFlag = 0;// 用于删除list数据 标识
					List<Long> ids = new ArrayList<>();
					for (Object dataT : datasTemp) {
						if (((BaseDataEntity) dataT).getId() != null) {
							ids.add(((BaseDataEntity) dataT).getId());// 已存在的id避免删除
						}
					}
					for (Object data : datasTemp) {
						if (data != null) {
							// 获取存取数据类名
							String dataSimpleClassName = data.getClass().getSimpleName();
							String dataClassName = data.getClass().getName();
							Class<?> clsData = Class.forName(dataClassName);
							// 护理计划如果是当周只修改或创建今天以后的数据
							if ("com.lmx.repoDomain.tmodel.CustomerNursingPlan".equals(entityClassName)) {// 特例护理计划
								dslJpaService.setEntityClass(clsData);
								// 判断是否是当周
								Date now = new Date();
								Integer yearNow = now.getYear() + 1900;
								Integer weekTab = CommonUtil.getWeek(now);
								// if (weekTab == 0)weekTab = 7;
								int weekIndex = CommonUtil.getWeekIndexFromSun(now);
								String pMethodName0 = "getYearTab";
								Method getPmethod0 = clsData.getDeclaredMethod(pMethodName0);
								int dataYearTab = (int) getPmethod0.invoke(data);// 调用getYearTab方法
								String pMethodName = "getWeekIndex";
								Method getPmethod = clsData.getDeclaredMethod(pMethodName);
								int dataWeekIndex = (int) getPmethod.invoke(data);// 调用getWeekIndex方法
								String pMethodName2 = "getWeekTab";
								Method getPmethod2 = clsData.getDeclaredMethod(pMethodName2);
								int dataWeekTab = (int) getPmethod2.invoke(data);// 调用getWeekTab方法
								if (yearNow == dataYearTab && weekIndex == dataWeekIndex && dataWeekTab < weekTab) {// 当天之前的护理计划不做操作

								} else {
									// 存在id则update 否则create
									if (((BaseDataEntity) data).getId() == null) {
										if (((BaseDataEntity) data).getDelStatus() == null
												|| ((BaseDataEntity) data).getDelStatus() != 1) {
											dslJpaService.create((BaseDataEntity) data);
										}
									} else {
										dslJpaService.update((BaseDataEntity) data);
									}
									datas.add(data);
								}
							} else {// payload 正常保存 存储前删除数据并新建或者修改数据
								if (notPayloadData) {
									// 增加多对一关联,多加了一个判断,一的一端可能没有多的一端的实体,需要判断一下field有无ytche
									if (deleteFlag == 0 && this.checkFieldExit(clsData, pName)) {
										deleteFlag = 1;
										// 删除父类先前所对应数据
										try {
											commonService.deleteEntity(dataSimpleClassName, pName, bd.getId(), ids);
										} catch (Exception e) {
											logger.debug("base delete error3 " + dataSimpleClassName + " " + pName + " "
													+ bd.getId() + " " + ids.toString() + " " + e);
										}
									}
									// 设置reverse类的值
									if (!"com.lmx.repoDomain.tmodel.Tenant".equals(entityClassName)) {
										// 增加多对一关联,一的一端可能没有多的一端的实体,需要判断一下field有无ytche
										if (this.checkFieldExit(clsData, pName)) {
											String pMethodName = "set" + pName.replaceFirst(pName.substring(0, 1),
													pName.substring(0, 1).toUpperCase());
											Method setPmethod = clsData.getDeclaredMethod(pMethodName,
													Class.forName(entityClassName));
											setPmethod.invoke(data, bd);// 调用set方法设置reverse类的值
										}
									} else {
										String pMethodName = "set" + pName.replaceFirst(pName.substring(0, 1),
												pName.substring(0, 1).toUpperCase());
										Method setPmethod = clsData.getSuperclass().getDeclaredMethod(pMethodName,
												Class.forName(entityClassName));
										setPmethod.invoke(data, bd);// 调用父类set方法暂仅限于设置tenant
									}
								}
								// 存在id则update 否则create
								dslJpaService.setEntityClass(clsData);
								if (((BaseDataEntity) data).getId() == null) {
									if (((BaseDataEntity) data).getDelStatus() == null
											|| ((BaseDataEntity) data).getDelStatus() != 1) {
										dslJpaService.create((BaseDataEntity) data);
									}
								} else {
									dslJpaService.update((BaseDataEntity) data);
								}
								datas.add(data);
							}
						}
					}
					// 将保存后的list datas 放入reverse类中
					if (datas.size() > 0) {
						Class<?> clsEntity = Class.forName(entityClassName);
						dslJpaService.setEntityClass(clsEntity);
						String methodName = "set"
								+ key.replaceFirst(key.substring(0, 1), key.substring(0, 1).toUpperCase());
						Method setMethod = this.findMethodWithoutParam(clsEntity, methodName);
						if (setMethod != null) {
							Parameter[] params = setMethod.getParameters();
							if (params != null && params.length > 0) {
								// 一对多关联set List;多对一关联set Entity
								if (List.class.isAssignableFrom(params[0].getType())) {
									setMethod.invoke(bd, datas);
								} else {
									setMethod.invoke(bd, datas.get(0));
									dslJpaService.setEntityClass(entity.getClass());
									dslJpaService.update(bd);
								}
							}
						}
					}
					// 设置payload 外壳 id
					//dslJpaService.setEntityClass(Class.forName(entityClassName));
					if (!notPayloadData) { // huibati
						bd.setId(1L);
					}
				}
			}
		} catch (Exception e) {
			logger.error("payload save error", e);
		}

		return (S) bd;
	}

	/**
	 * 忽略参数列表获取方法(调用前确定该方法没有被重载)
	 *
	 * @author ytche
	 * @param clsEntity
	 * @param methodName
	 * @return
	 * @date 2017年5月24日 下午3:18:14
	 */
	private Method findMethodWithoutParam(Class<?> clsEntity, String methodName) {
		Method[] methods = clsEntity.getMethods();
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				return method;
			}
		}
		return null;
	}

	/**
	 * 判断一个类是否存在某个字段
	 *
	 * @author ytche
	 * @param clsData
	 * @param pName
	 * @return
	 * @date 2017年5月24日 下午2:44:48
	 */
	private boolean checkFieldExit(Class<?> clsData, String pName) {
		boolean rtn = false;
		Field[] fields = clsData.getDeclaredFields();
		for (Field field : fields) {
			if (field.getName().equals(pName)) {
				rtn = true;
				break;
			}
		}
		return rtn;
	}

	/**
	 * 判断是否居家请求
	 *
	 * @author ytche
	 * @return
	 * @date 2017年6月5日 下午2:59:27
	 */
	protected Boolean checkJujia() {
		Integer contextType = ActionContextHolder.getContext().getType();
		return contextType != null && contextType.equals(ICommonConstants.SYSTEM_TYPE_JUJIA_2);
	}
}
